
#pragma once

#include <string>
#include <vector>

//Defines player.
enum Player
{
	None,
	Player1,
	Player2
};

//Represents single dot.
struct Dot
{
	private:
		Player _owner;			//owner of this dot.
		int _tag1;				//tag #1. Will be used for area filling.
		int _tag2;				//tag #2. Will be used for area filling.
	public:
		//Creates empty dot.
		inline Dot()
		{
			_owner = None;
			_tag1 = 0;
			_tag2 = 0;
		}
		//Returns current owner.
		inline Player GetOwner()
		{ return _owner; }
		//Sets new owner.
		inline void SetOwner(Player owner)
		{ _owner = owner; }
		//Returns auxiliary tag.
		inline int GetTag1()
		{ return _tag1; }
		//Sets auxiliary tag.
		inline void SetTag1(int value)
		{ _tag1 = value; }

		inline int GetTag2()
		{ return _tag1; }

		inline void SetTag2(int value)
		{ _tag1 = value; }
};

//Represents player action (request to own new dot).
class GameAction
{
	private:
		Player _player;
		size_t _x, _y;
	public:
		inline GameAction()
		{
			_player = None;
			_x = 0;
			_y = 0;
		}
		inline GameAction(Player player, size_t x, size_t y)
		{
			_player = player;
			_x = x;
			_y = y;
		}

		inline Player GetPlayer() const
		{ return _player; }

		inline size_t GetX() const
		{ return _x; }

		inline size_t GetY() const
		{ return _y; }
};

//Groups all dots into one field.
class GameField
{
	private:
		size_t _width;
		size_t _height;
		std::vector<Dot> _data;
	public:
		//Creates field with given size.
		inline GameField(size_t width, size_t height)
			:_data(width * height)
		{
			_width = width;
			_height = height;
		}

		inline size_t GetWidth()
		{ return _width; }

		inline size_t GetHeight()
		{ return _height; }

		inline Dot &operator () (size_t x, size_t y)
		{ return _data[x + y * _width]; }
};

//Contains information about players and game statistics.
class GameInfo
{
	public:
		enum Status
		{
			Started,
			NotStarted
		};
	private:
		std::string _player1;
		std::string _player2;
		Status _status;
	public:
		//Creates "Started" game.
		inline GameInfo(const char *player1, const char *player2)
		{
			_player1 = player1;
			_player2 = player2;
			_status = Started;
		}
		//Creates "NotStarted" game.
		inline GameInfo(const char *player1)
		{
			_player1 = player1;
			_status = NotStarted;
		}
		Status GetStatus()
		{ return _status; }
		//Returns name of the first player.
		inline const char *GetPlayer1()
		{ return _player1.c_str(); }
		//Returns name of the second player.
		inline const char *GetPlayer2()
		{ return _player2.c_str(); }
		//Sets name of the second player and marks game as started.
		inline void SetPlayer2(const char *name)
		{
			_player2 = name;
			_status = Started;
		}
};

//Base class. Contains sufficient information about one game.
class Game
{
	private:
		GameField _field;
		GameAction _lastAction;
		GameInfo _info;
	public:
		inline Game(size_t fieldWidth, size_t fieldHeight,
					const char *player1, const char *player2)
			:_field(fieldWidth, fieldHeight), _info(player1, player2)
		{
			//nothing
		}
		inline Game(size_t fieldWidth, size_t fieldHeight, const char *player1)
			:_field(fieldWidth, fieldHeight), _info(player1)
		{
			//nothing
		}
		//Returns game field.
		GameField &GetField()
		{ return _field; }
		//Returns last action.
		inline GameAction &getLastAction()
		{ return _lastAction; }
		//Returns current player.
		inline Player GetCurrentPlayer()
		{
			switch (_lastAction.GetPlayer())
			{
				case Player1:
					return Player2;
				case None:
				case Player2:
				default:
					return Player1;
			}
		}
		//Returns info about game and some statistics.
		GameInfo &GetInfo()
		{ return _info; }
		//Applies player action.
		void ApplyAction(const GameAction &action);
		//Returns count of dots, that are owned by each player.
		void GetDotsCount(size_t &player1, size_t &player2, size_t &untaken);
};